將一個值從某個型別轉換至另一個型別的動作,叫做「型別轉換(type casting)」。
因為值的使用規則而被迫轉型的,叫做「強制轉型(coercion)」。
JS強制轉型(coercion)的結果永遠都會是純量的基型值。
明確的強制轉型:能夠從程式碼看出型別轉換動作是刻意進行的。
隱含的強制轉型:型別轉換因其他作業而產生較不明顯的副作用。
執行b = a + ""
,由於+
的運算子,其中一個運算元是string
的話,那這個運算式就會執行string
的串接動作,而(隱藏)的副作用,就是會將42(number)
轉換成"42"(string)
。
至於c = String( a )
,則是很明顯地將a
的值明確地換成string
。
以上2者都可以達到相同的效果:42(number)
轉換成"42"(string)
。
如果你很清楚執行b = a + ""
的結果,那這個執行對你來說,是「明確」的;但不清楚c = String( a )
的結果,這個執行則算是「隱含」的。
要記住的一點是,我們撰寫的程式碼,很少是給自己看的。就算已經是專家等級了,但還是得考慮到團隊成員的程度,對他們來說,你的「明確」與「隱含」是否是他們能理解的呢?
將任何非string值強制轉型成string表示值。
基型值的轉型:null
=>"null"
、undefined
=>"undefined
、"true
=>"true"
如果物件本身擁有自己的toString( )
方法,而這個物件被當作string
使用,那它的toString( )
就會被自動呼叫。
array的toString( )
結果:
輸出string,每個值都以" , "隔開。
如果有任何非number值被當作number值來使用,就會進行轉換,例如數學運算。
基型值的轉型:tru1
=>1
、undefined
=>NaN
、但是null
=>0
。
object和array會先轉成他們的基型等效值,如若不是一個number值,會再次轉型為number值。
再轉型之前,JS會先確認目標值是否有valueOf( )
方法,若有且回傳基型值的話,那個值就會被用於強制轉型;如果沒有valueOf( )
方法,會使用toString( )
方法(如果有的話)。
如果以上2種執行都無法提供基型值的話,就會擲出TypeError。
在其他程式語言中,1與0分別代表true與false,但在JS中number就是number,boolean就是boolean。可以把1強制轉型成true,0強制轉型成false(反之亦然),但實際上,他們並不相同。
1並不等於true,0也不等於false。
JS所有的值可以被分為2種:被強制轉型為boolean型別後,不是true就是false。
會被稱為「falsy(假值的)」的值:
以上的值,如果轉型成boolean會成為flase。
如果某個值不在這清單上,那已較合乎邏輯的想法,我們可以判定它就在另一個清單「truthy」上。
d的結果為true。請注意,以上的值雖然乍看之下會轉為false,但實際上,它們的型別都是string,既然如此,結果當然為true。
d的結果仍為true。切記,只要是沒在falsy清單的值,都為truthy值。
truthy與flasy的重要性在於,一個值轉型成boolean時,會有怎樣的行為。
直接看範例:String( )
方法會把任何值強制轉型成string,Number( )
方法則是會把任何值強制轉型成number。
以上的方式之所以稱為「明確轉型」,是因為可以從程式碼很明顯的看出執行作業的結果。
除了上述的方式之外,也有其他方式能進行「明確轉型」:
執行a.toString( )
,從表面看來,toString( )
是執行了「明確轉型」,但這裡有個「隱含轉型」的存在。toString( )
是個方法,所以無法用在像是42這種基型值上。JS會自動地把42「封裝」在一個物件包裹器(object wrapper)之中,如此一來,便具有object的行為了,就能呼叫toString( )
。
至於+c
,這個看起來很特別的運算式,只有單一運算元的運算子,不會執行數學運算或string的串接。+
運算子會明確地把它的運算元轉型成number值。
-
運算子也會像+
一樣轉型,但它會反轉數值的正負號。且我們不能把2個相鄰的符號放在一起(--)
,這樣會被解讀為遞減運算子,應該要在中間加上空格,- -"3.14"
。
如果會與其他運算子緊密相鄰,應該就要避免使用單一運算子的方式來進行強制轉換,以免造成混淆。
單一+
運算子的另一個用途是將Date object強制轉型成number,結果會是那個日期時間值的unix時間戳(從1970年1月1日 00:00:00 UTC 開始,所經過的毫秒數)。
取得當下的時間戳:
有2種非強制轉型的方式:
以及ES5新增的,建議使用
將一個string的內容剖析出number的動作,可以達成類似將string強制轉換成number的效果,但這種執行與之前討論的string轉型成number還是有所差異。
剖析數值的動作能夠接受非數值字元,從左至右剖析,遇到非數值字元便會停止,輸出剖析成功的數值。
強制轉型無法接受任何非數值字元,轉型會失敗,產生NaN。
如果對於剖析的對象並無要求是否全部為數值,可以使用parseInt( )
,但若只能接受數字,譬如"42px"不該視為數字的話,那就使用強制轉型。
parseInt( )
只能用於string值。如果傳入一個非string值,該值會先被強制轉型為string,這是一種隱含地強制轉型,這是不好的,請避免這種行為。
使用Boolean( )
進行強制轉型:
結果為true
結果為false
雖然Boolean( )
可以明確地轉型,但並不普遍。
如同+
運算子一樣,!
也會強制地將某個值轉型成反向的Boolean值,因此我們會使用!!
雙否定運算子再做一次反向。
if(...)
敘述式,會強制將值轉換為boolean。
上面為三元運算子(ternary operator),會依據a的boolean值,判斷指定true或false給b。
表面看起來是明確地強制轉換,但實際上,a運算式會隱含地強制轉型成boolean,才能進行判斷。
就明確轉型來說,Boolean(a)
和!!a
都是比較好的選擇。
此為You Don't Know JS系列的筆記。